
package jogs.net.tableserver; 

import jogs.core.*;
import jogs.games.Game;

import java.util.*;
import java.net.*;
import java.io.*;
import java.sql.*;

/**
 * ClientHandler inner class
 */
public class TSClientHandler extends Thread
{
  private Socket clientSocket; 
  private TableServer ts;
  private BufferedReader in;
  private PrintStream out; 
  protected boolean disconnected; 

  // 0 = don't know yet
  // 1 = gameroomserver
  // 2 = player
  private int clientType; 

  private String username; 

  public TSClientHandler(Socket _clientSocket, TableServer _ts, int _ct)
  {
    in = null;
    out = null; 
    clientSocket = _clientSocket; 
    ts = _ts; 
    disconnected = false; 
    clientType = _ct; 
  }

  public void send(String msg)
  {
    if (out != null) out.println(msg);
  }

  private synchronized void disconnect()
  {
    System.out.println (username + " is disconnecting..."); 

    disconnected = true; 
    in = null;
    out = null; 
    ts.removeClient(this); 

    try 
    {
      clientSocket.close(); 
    }
    catch(Exception e) { e.printStackTrace(); }
    
    System.out.println (username + " has been disconnected"); 
  }

  public void run()
  {
    if (clientType == 1) {
      run_gameroomserver(); 
      return; 
    }
    else if (clientType == 2) { 
      run_tableserver();
      return; 
    }

    try
    {
      in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); 
      out = new PrintStream(clientSocket.getOutputStream()); 
      int authenticated = 0;
      
      while (authenticated == 0)
      {
        out.println("@AUTHENTICATE:");
        String un = in.readLine(); 
        String pw = in.readLine(); 
        
        if (un == null || pw == null)
        {
          System.out.println("bogus data from gameroomserver.. gameroomserver died? killing this TSSClientHandler..");
          return;
        }

        authenticated = ts.authenticate(un, pw);
        username = un;  
      }

      out.println("@LOGINSUCC:"); 

      if (authenticated == 1)
      {
        System.out.println("authenticated = 1"); 

        // it's the game room server!
        ts.grs = new TSClientHandler(clientSocket, ts, 1); 
        ts.grs.start(); 

        return;
      }
      else if (authenticated == 2)
      {
        System.out.println("authenticated = 2"); 

        // it's a player 
        // (let's delay making this client a Player object until the game starts)
        // so when the users at the table are just chatting, they're still just 
        // TSClientHandlers. 
        clientType = 2; 
        run_tableserver(); 
        
        //Player newPlayer = new Player(clientSocket, ts);
        //newPlayer.start(); // add him to a client list after he sends a join
        return; 
      }
    }
    catch(Exception e)
    {
      System.out.println("Caught exception in client handler.. client stopping."); 
      e.printStackTrace(); 
      disconnected = true;  
    }
  }

  void run_gameroomserver()
  {
    System.out.println("Starting gameroomserver client handler."); 

    try
    {
      in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); 
      out = new PrintStream(clientSocket.getOutputStream()); 
    
      String line = ""; 
      while (line != null)
      {
        line = in.readLine(); 
        
        // respond to the request from the metaserver 

        handle_grs_request(line); 
      }
    }
    catch(Exception e)
    {
      System.out.println("Caught exception in client handler.. client stopping."); 
      e.printStackTrace(); 
      disconnected = true;  
    }
  }

  // --- 

  boolean handle_grs_request(String line)
  {
    if(line == null)
      return true;
    String details = null;
    String command = null;
  
    //all commands start with a @ and end with a : 
    int begin = line.indexOf('@');
    int end = line.indexOf(':');
    
    //if @ and : are not in message than it is not a command
    if(begin == -1 || end == -1)
    {
      //this.send("@ERROR:Not a valid command");
      return false;
    }
    
    //get the command out of the message
    command = line.substring(begin, end);
    
    //if command has details
    if(line.length() > end+1)
      details = line.substring(end+1);
    //System.out.println("command: " + command);
    //System.out.println("details: " + details);

    if (command.equals("@GET_CLIENT_COUNT"))
      out.println("" + ts.getClientCount()); 
    else if (command.equals("@GET_NAME"))
      out.println(ts.name); 
    else if (command.startsWith("@ADDKEYPASS"))
    {
      //System.out.println("details=" + details); 
      String[] parts = details.split(","); 
      String user = parts[0];
      String keypass = parts[1]; 
      ts.addKeyPass(user, keypass); 
      out.println("@OK_ADDKEYPASS:");
    }
    else 
      return false; 

    return true; 
  }

  // for users that have not turned into players yet
  void run_tableserver()
  {
    System.out.println("Starting table server client handler."); 
    ts.addClient(this); 

    try
    {
      in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); 
      out = new PrintStream(clientSocket.getOutputStream()); 

      // tell everyone he's here
      ts.broadcast("@SAT:"+username); 
    
      String line = ""; 
      while (line != null)
      {
        line = in.readLine(); 
        
        // respond to the request from the metaserver 

        handle_ts_request(line); 

        if (disconnected)
          return; 
      }
    }
    catch(Exception e)
    {
      System.out.println("Caught exception in client handler.. client stopping."); 
      e.printStackTrace(); 
      disconnected = true;  
    }
  }

  String handleCreateGame(String details) 
  {
    // details should be game name only, set default options 
    // options will be added with a separate /options command by the creator

    // before creating the player thread, let's check to see if it's a valid game
    // first. 
    // 
    // maxplayers = -1 means no max for now?
  
    String gameName = "somename"; // should get this from details
    String gameType = details; 
    int max = -1; 

	  Game g = Game.newGame(gameName, gameType, ts, max); 

    if (g == null) 
      return "Game does not exist";

    if (ts.theGame != null)
      return "Table in use";

    // now create the player
	  Player player = new Player(clientSocket, ts, username);
    
    g = ts.createGame(details, gameName, max, player);
    if (g == null)
      return "Problem creating game"; 

    ts.removeClient(this); 
    ts.addPlayer(username, player); 
    player.start(); 

    // i think we have to make all the rest of the clients into players as well
    // because it will be hard to keep both clients and players... 

    return null; 
  }
  
  boolean handle_ts_request(String line)
  {
    if(line == null)
      return true;
    String details = null;
    String command = null;
  
    //all commands start with a @ and end with a : 
    int begin = line.indexOf('@');
    int end = line.indexOf(':');
    
    //if @ and : are not in message than it is not a command
    if(begin == -1 || end == -1)
    {
      //this.send("@ERROR:Not a valid command");
      return false;
    }
    
    //get the command out of the message
    command = line.substring(begin, end);
    
    //if command has details
    if(line.length() > end+1)
      details = line.substring(end+1);
    //System.out.println("command: " + command);
    //System.out.println("details: " + details);

    if (command.equals("@CHAT"))
      ts.broadcast("@CHAT:" + username + ": " + details); 
    else if (command.equals("@DISC"))
      disconnect(); 
    else if (command.equals("@CREATE"))
    {
      String created = handleCreateGame(details); 
      if (created != null)
        send("@ERROR_CREATE:"+created); 
      else
      {
        System.out.println("Game created, ending client thread (player thread started)!"); 
        disconnected = true; // to end this thread
                             // Player thread takes over from here
      }
    }
    else 
    {
      System.out.println("Unrecognized command: " + command); 
      return false; 
    }

    return true; 
  }

}

